/**
 *Glogger.java
 *@anthor Daniel Liu
 *2006-4-26 3:18:35
 **/
package org.lex.utils.logging;

import java.util.Vector;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.swing.SwingWorker;

import org.lex.awt.Location;
import org.lex.utils.logging.handler.LoggerMainFrame;
import org.lex.utils.logging.handler.WindowHandler;


public class LogFactory {
	private static final Level DEFAULT_LEVEL = Level.FINE;

	// =======================================================
	private static Formatter formatter = new TinyFormatter();
	// TODO Logger������Ӧ�ô洢��һ��֧�ֿ�������/�������ݽṹ��,Vector������?
	private static Vector<String> loggerNames = new Vector<String>();
	private static LoggerMainFrame frame = null;
	private static boolean windowHandlerEnabled = true;

	public static Logger getLog(String name) {
		return getLog(name, DEFAULT_LEVEL);
	}

	public static Logger getLog(Class<?> className) {
		return getLog(className.getName());
	}

	public static Logger getLog(Class<?> className, Level level) {
		return getLog(className.getName(), level);
	}

	public static Logger getLog(String name, Level level) {
		Logger logger = Logger.getLogger(name);
		for (String s : loggerNames)
			if (true == s.equals(name))
				return logger;
		// ==============================
		// ���������һ���µ�logger����Ҫ��ʼ��
		// ==============================
		loggerNames.add(name);
		setLevel(logger, level);
		return logger;
	}

	/**
	 * ����Logger���?����<b>����</b>��Handler��Level
	 */
	public static void setLevel(Logger log, Level level) {
		if (null == log)
			return;
		log.setLevel(level);
		Handler[] handlers = log.getHandlers();
		for (Handler handler : handlers)
			handler.setLevel(level);
	}

	/**
	 * ����Logger���?����<b>ʹ��</b>��Handler��Level
	 * ����Loggerʹ�������parent��Handler����ô��ЩHandler��LevelҲ�ᱻ�ı�
	 * �����������parent logger�����ᱻ�ı�
	 */
	public static void setLevelRecursively(Logger log, Level level) {
		if (null == log)
			return;
		log.setLevel(level);
		while (true) {
			if (null == log)
				break;
			Handler[] handlers = log.getHandlers();
			for (int i = 0; i < handlers.length; i++)
				handlers[i].setLevel(level);
			if (true == log.getUseParentHandlers())
				log = log.getParent();
			else
				break;
		}
	}

	// TODO �����ƺ��е�"�ʲ�����"...
	/**
	 * ����Logger��level��������null�Ļ�˵��level�Ǽ̳������parent��
	 * Ӧ�ü������ϲ��ң�ֱ��level����nullΪֹ �ܱ�֤���صĲ�����nullֵ
	 */
	public static Level getLevelRecursively(Logger log) {
		while (true) {
			if (null == log)
				return DEFAULT_LEVEL;
			if (null != log.getLevel())
				return log.getLevel();
			log = log.getParent();
		}
	}

	public static void setWindowHandlerEnabled(boolean value) {
		windowHandlerEnabled = value;
	}

	public static boolean isWindowHandlerEnabled() {
		return windowHandlerEnabled;
	}

	public static boolean addWindowHandler(final Logger log) {
		// FIXME WindowHandler��ν��ã�����Ҫ����
		if (false == isWindowHandlerEnabled())
			return false;
		new SwingWorker() {
			protected Object doInBackground() {
				WindowHandler wh = new WindowHandler();
				wh.getHandler().setLevel(getLevelRecursively(log));
				log.addHandler(wh.getHandler());
				Location.moveTo(wh, Location.SOUTH_EAST);
				wh.setTitle(log.getName());
				wh.setVisible(true);
				return null;
			}
		}.execute();
		return true;
	}

	public static void removeWindowHandlerRecursively(Logger log) {
		WindowHandler wh = new WindowHandler();
		wh.getHandler().setLevel(getLevelRecursively(log));
		log.addHandler(wh.getHandler());
		Location.moveTo(wh, Location.SOUTH_EAST);
		wh.setTitle(log.getName());
		wh.setVisible(true);
	}

	static LoggerMainFrame getFrame() {
		if (null == frame) {
			frame = new LoggerMainFrame();
			frame.setVisible(true);
		}
		return frame;
	}

	public static Formatter getFormatter() {
		return formatter;
	}

	public static void setFormatter(Formatter formatter) {
		LogFactory.formatter = formatter;
	}
}
